package com.mdp.workflow.biz.hi.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.mdp.core.service.BaseService;
import com.mdp.safe.client.entity.User;
import com.mdp.safe.client.utils.LoginUtils;
import com.mdp.workflow.api.FlowMsgService;
import com.mdp.workflow.api.FlowProcinstService;
import com.mdp.workflow.biz.hi.convert.FlowProcinstConvert;
import com.mdp.workflow.biz.hi.entity.Procinst;
import com.mdp.workflow.biz.hi.mapper.ProcinstMapper;
import com.mdp.workflow.bus.publisher.FlowProcinstEventPublisher;
import com.mdp.workflow.comm.dict.DeleteReason;
import com.mdp.workflow.comm.dict.ProcinstConstants;
import com.mdp.workflow.comm.dict.ProcinstStatus;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 父类已经支持增删改查操作,因此,即使本类什么也不写,也已经可以满足一般的增删改查操作了.<br> 
 * 组织 com.mdp  顶级模块 workflow 大模块 hi 小模块 <br>
 * 实体 Procinst 表 act_hi_procinst 当前主键(包括多主键): id_; 
 ***/
@Service("mdp.workflow.hi.ProcinstService")
public class ProcinstService extends BaseService<ProcinstMapper, Procinst> implements FlowProcinstService {

	@Resource
	private RuntimeService runtimeService;
	@Resource
	private HistoryService historyService;

	static Logger logger =LoggerFactory.getLogger(ProcinstService.class);

	@Autowired
	FlowMsgService flowMsgService;

	@Autowired
	FlowProcinstEventPublisher flowProcinstEventPublisher;

	/**
	 * 自定义查询，支持多表关联
	 * @param page 分页条件
	 * @param ew 一定要，并且必须加@Param("ew")注解
	 * @param ext 如果xml中需要根据某些值进行特殊处理，可以通过这个进行传递，非必须，注解也可以不加
	 * @return
	 */
	public List<Map<String,Object>> selectListMapByWhere(IPage page, QueryWrapper ew, Map<String,Object> ext){
		return baseMapper.selectListMapByWhere(page,ew,ext);
	}



	@Override
	public ProcessInstance getProcessInstance(String id) {
		return runtimeService.createProcessInstanceQuery()
				.includeProcessVariables()
				.processInstanceId(id)
				.singleResult();
	}

	@Override
	public List<ProcessInstance> getProcessInstances(Set<String> ids) {
		return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
	}

	@Override
	public HistoricProcessInstance getHistoricProcessInstance(String id) {
		return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult();
	}

	@Override
	public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
		return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
	}

	@Override
	public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) {

	}

	@Override
	public void updateProcessInstanceWhenApprove(ProcessInstance instance) {
		// 1. 更新流程实例 status
		runtimeService.setVariable(instance.getId(), ProcinstConstants.PROCINST_STATUS,
				ProcinstStatus.APPROVE.getStatus());

		// 2. 发送流程被【通过】的消息
		User user= LoginUtils.getCurrentUserInfo();
 		flowMsgService.pushMsg(user,instance.getStartUserId(),"",String.format("您发起的流程【%s】已审核通过!",instance.getName()),null);
		// 3. 发送流程实例的状态事件
		// 注意：此时如果去查询 ProcessInstance 的话，字段是不全的，所以去查询了 HistoricProcessInstance
		HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId());
		flowProcinstEventPublisher.sendProcessInstanceResultEvent(
				FlowProcinstConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, ProcinstStatus.APPROVE.getStatus()));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateProcessInstanceReject(String id, String reason) {
		// 1. 更新流程实例 status
		runtimeService.setVariable(id, ProcinstConstants.PROCINST_STATUS, ProcinstStatus.REJECT.getStatus());

		// 2. 删除流程实例，以实现驳回任务时，取消整个审批流程
		ProcessInstance processInstance = getProcessInstance(id);
		deleteProcessInstance(id, StrUtil.format(DeleteReason.REJECT_TASK.format(reason)));

		// 3. 发送流程被【不通过】的消息
		flowMsgService.pushMsg(LoginUtils.getCurrentUserInfo(),processInstance.getStartUserId(),"",StrUtil.format(DeleteReason.REJECT_TASK.format(reason)),null);

		// 4. 发送流程实例的状态事件
		flowProcinstEventPublisher.sendProcessInstanceResultEvent(
				FlowProcinstConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, ProcinstStatus.REJECT.getStatus()));
	}
	@Override
	public void deleteProcessInstance(String id, String reason) {
		runtimeService.deleteProcessInstance(id, reason);
	}


}

